#include "airc-cmds.h"

#define IRC_USER_CMD(cmd, help) {#cmd, airc_usercmd_ ## cmd, help, 0 }

#if 0
struct _airc_usercmd airc_usercmds[] = {
    IRC_USER_CMD(action, "action &lt;action to perform&gt;: Perform an action."),
    IRC_USER_CMD(away, "away [message]:  Set an away message. To return from away, do not supply a message."),
    IRC_USER_CMD(ban, "ban [channel] &lt;user&gt;: Ban a user from a channel."),
    IRC_USER_CMD(chanserv, "chanserv &lt;message&gt;: Send a message to ChanServ."),
    IRC_USER_CMD(cs, "cs &lt;message&gt;: Send a message to ChanServ."),
    IRC_USER_CMD(ctcp, "ctcp &lt;user&gt; &lt;message&gt;: Send a CTCP message to a user."),
    IRC_USER_CMD(cycle, "cycle [channel]: Part and then rejoin a channel."),
    IRC_USER_CMD(deop, "deop [channel] <user>: Deop a user in a channel."),
    IRC_USER_CMD(devoice, "devoice [channel] <user>: Devoice a user in a channel."),
    IRC_USER_CMD(helpop, "helpop [command]: Query the network help system. For commands unsupported by the client, use /quote COMMAND."),
    IRC_USER_CMD(hostserv, "hostserv <message>: Send a message to hostserv"),
    IRC_USER_CMD(hs, "hs <message>: Send a message to hostserv"),
    IRC_USER_CMD(ignore, "ignore <user>: Block messages from a user."),
    IRC_USER_CMD(invite, "invite [channel] <user>: Invite a user into a channel."),
    IRC_USER_CMD(ison, "ison <user>: Check to see if a user is online."),
    IRC_USER_CMD(j, "j <channel>[,channel2,...] [key1 key2 ...]: Join a channel. A key may be required to join some channels."),
    IRC_USER_CMD(join, "join <channel>[,channel2,...] [key1 key2 ...]: Join a channel. A key may be required to join some channels."),
    IRC_USER_CMD(kick, "kick [channel] <user> [message]: Remove a user from a channel with the given optional message."),
    IRC_USER_CMD(kill, "kill <user> [message]: Remove a user from a server. You need to be a server operator to use this command."),
    IRC_USER_CMD(knock, "knock <channel>: Send a request to an invite-only channel to let you in."),
    IRC_USER_CMD(list, "list [search]: Request a list of available channels on the network."),
    IRC_USER_CMD(links, "links: Display the server links on the network."),
    IRC_USER_CMD(map, "map: Display a map of the network layout."),
    IRC_USER_CMD(me, "me &lt;action to perform&gt;: Perform an action."),
    IRC_USER_CMD(memoserv, "memoserv <message>: Send a message to memoserv."),
    IRC_USER_CMD(mode, "mode [channel] [modes]: Sets the modes of a channel. If you supply nothing, this displays the current modes."),
    IRC_USER_CMD(motd, "motd: Request the Message of the Day of the connected server."),
    IRC_USER_CMD(msg, "msg <user> <message>: Send a message to a user."),
    IRC_USER_CMD(ms, "ms <message>: Send a message to memoserv."),
    IRC_USER_CMD(names, "names [channel]: Request the list of users in a channel."),
    IRC_USER_CMD(nick, "nick <new nick>: Change your nickname."),
    IRC_USER_CMD(nickserv, "nickserv <message>: Send a message to nickserv."),
    IRC_USER_CMD(notice, "notice [target] <message>: Send a notice to a user or channel."),
    IRC_USER_CMD(ns, "ns <message>: Send a message to nickserv."),
    IRC_USER_CMD(op, "op [channel] <user>: Op a user in a channel."),
    IRC_USER_CMD(oper, "oper <name> <password>: Login as a server operator. Only use this if you have permission to do so."),
    IRC_USER_CMD(operserv, "operserv <message>: Send a message to operserv. This service is usually reserved for server operators."),
    IRC_USER_CMD(os, "os <message>: Send a message to operserv. This service is usually reserved for server operators."),
    IRC_USER_CMD(part, "part [channel] [message]: Leave a channel with a given optional message."),
    IRC_USER_CMD(ping, "ping [user]: Test lag between a user if specified. Otherwise, check lag with server."),
    IRC_USER_CMD(privmsg, "privmsg <target> <message>: Send a message to a user or channel."),
    IRC_USER_CMD(query, "query <user> [message]: Opens a chat with a user."),
    IRC_USER_CMD(quit, "quit [message]: Disconnect from the server with an optional message."),
    IRC_USER_CMD(quote, "quote <raw command>: Send a raw command to the server."),
    IRC_USER_CMD(raw, "raw <raw command>: Send a raw command to the server."),
    IRC_USER_CMD(remove, "remove [channel] <user> [message]: Remove a user from a channel with an optional message."),
    IRC_USER_CMD(time, "time: Get the server's local time."),
    IRC_USER_CMD(topic, "topic [channel] [message]: Set the topic of a channel. If you do not supply a message, it displays the current topic."),
    IRC_USER_CMD(umode, "umode [modes]: Set modes on yourself."),
    IRC_USER_CMD(unignore, "unignore <user>: Unblocks a user."),
    IRC_USER_CMD(version, "version [nick]: Get the client of a user."),
    IRC_USER_CMD(voice, "voice [channel] <nick>: Voice a user in a channel."),
    IRC_USER_CMD(wallops, "wallops <message>: Sends a message to other server operators. You need to be a server operator to use this."),
    IRC_USER_CMD(watch, "watch [+/-][user]: Add or remove a user from a watch list. You will be notified when a user on a watch list comes online."),
    IRC_USER_CMD(who, "who [search]: Lookup users matching a given search. Use <i>/helpop who</i> for more information."),
    IRC_USER_CMD(whois, "whois [server] <user>: Get information about a user who is currently online."),
    IRC_USER_CMD(whowas, "whowas <user>: Get information about a user who is no longer online."),
    {NULL, NULL, NULL, 0},
};
#endif
struct _airc_usercmd airc_usercmds[] = {
    IRC_USER_CMD(away, "away [message]:  Set an away message. To return from away, do not supply a message."),
    IRC_USER_CMD(ctcp, "ctcp &lt;user&gt; &lt;message&gt;: Send a CTCP message to a user."),
    IRC_USER_CMD(j, "j <channel>[,channel2,...] [key1 key2 ...]: Join a channel. A key may be required to join some channels."),
    IRC_USER_CMD(join, "join <channel>[,channel2,...] [key1 key2 ...]: Join a channel. A key may be required to join some channels."),
    IRC_USER_CMD(kick, "kick [channel] <user> [message]: Remove a user from a channel with the given optional message."),
    IRC_USER_CMD(list, "list [search]: Request a list of available channels on the network."),
    IRC_USER_CMD(me, "me &lt;action to perform&gt;: Perform an action."),
    IRC_USER_CMD(mode, "mode [channel] [modes]: Sets the modes of a channel. If you supply nothing, this displays the current modes."),
    IRC_USER_CMD(msg, "msg <user> <message>: Send a message to a user."),
    IRC_USER_CMD(notice, "notice [target] <message>: Send a notice to a user or channel."),
    IRC_USER_CMD(query, "query <user> [message]: Opens a chat with a user."),
    IRC_USER_CMD(quit, "quit [message]: Disconnect from the server with an optional message."),
    IRC_USER_CMD(quote, "quote <raw command>: Send a raw command to the server."),
    IRC_USER_CMD(raw, "raw <raw command>: Send a raw command to the server."),
    IRC_USER_CMD(topic, "topic [channel] [message]: Set the topic of a channel. If you do not supply a message, it displays the current topic."),
    IRC_USER_CMD(umode, "umode [modes]: Set modes on yourself."),
    IRC_USER_CMD(whois, "whois [server] <user>: Get information about a user who is currently online."),
    IRC_USER_CMD(whowas, "whowas <user>: Get information about a user who is no longer online."),
    {NULL, NULL, NULL, 0}
};

#undef IRC_USER_CMD

int airc_parse_rawcmd(IRC_conn *irc, const char *who, const char *raw){
        irc_send(irc, "%s", raw);
        return 1;
}

static PurpleCmdRet airc_parse_usercmd(PurpleConversation *conv,
    const gchar *usercmd, gchar **args, gchar **error, void *data){
    PurpleConnection *gc;
    IRC_conn *irc;
    struct _airc_usercmd *cmd;
    char *cmdname;

    gc = purple_conversation_get_gc(conv);
    if (!gc)
        return PURPLE_CMD_RET_FAILED;
    irc = IRCDATA(gc);
    for(cmd = airc_usercmds; (cmdname = cmd->name); cmd++){
        if(!g_ascii_strcasecmp(cmdname, usercmd))
            break;
    }
    if(!cmdname){
        return PURPLE_CMD_RET_FAILED;
    }
    (cmd->on_command)(irc, usercmd, purple_conversation_get_name(conv), (const char **)args);
    return PURPLE_CMD_RET_OK;
}

void airc_register_usercmds(void){
    struct _airc_usercmd *cmd;
    PurpleCmdFlag f;
    PurpleCmdPriority p;
    char args[] = "s";
    
    p = PURPLE_CMD_P_PRPL;
    f = PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM
        | PURPLE_CMD_FLAG_PRPL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS;
    for(cmd = airc_usercmds; cmd->name && cmd->on_command; cmd++){
        if(!(cmd->id = purple_cmd_register(cmd->name, args, p, f, "advanced-irc",
            airc_parse_usercmd, cmd->help, NULL))){
            purple_debug_info("airc", "Failed to load command: %s\n", cmd->name);
        }
    }
}

void airc_unregister_usercmds(void){
    struct _airc_usercmd *cmd;
    
    for(cmd = airc_usercmds; cmd->name && cmd->on_command; cmd++){
        if(cmd->id)
            purple_cmd_unregister(cmd->id);
    }
}

static int airc_channel_cmd(IRC_conn *irc, char *cmd, char *target, char **args){
    /* CMD #channel :arguments 
     * CMD #channel */
    char  **vargs;
    
    vargs = g_strsplit(args[0], " ", 2);
    if(!vargs){
        irc_send(irc, "%s %s", cmd, target);
        return 1;
    }
    if(airc_is_channel(irc, vargs[0])){
        if(vargs[1] && strlen(vargs[1]))
            irc_send(irc, "%s %s :%s", cmd, vargs[0], vargs[1]);
        else
            irc_send(irc, "%s %s", cmd, vargs[0]);
    }else{
        if(airc_is_channel(irc, target))
            irc_send(irc, "%s %s :%s", cmd, target, args[0]);
    }
    g_strfreev(vargs);
    return 1;
}

static int airc_channel_cmd1(IRC_conn *irc, char *cmd, char *target, char **args){
    /* CMD #channel arg0 :arguments 
     * CMD #channel arg0
     * CMD #channel*/
    char  **vargs;
    
    vargs = g_strsplit(args[0], " ", 3);
    if(!vargs){
        irc_send(irc, "%s %s", cmd, target);
        return 1;
    }
    if(airc_is_channel(irc, vargs[0])){
        if(vargs[1] && vargs[2])
            irc_send(irc, "%s %s %s :%s", cmd, vargs[0], vargs[1], vargs[2]);
        else if(vargs[1])
            irc_send(irc, "%s %s %s", cmd, vargs[0], vargs[1]);
        else
            irc_send(irc, "%s %s", cmd, vargs[0]);
    }else{
        if(airc_is_channel(irc, target)){
            if(vargs[1] && vargs[2])
                irc_send(irc, "%s %s %s :%s %s", cmd, target, vargs[0],
                    vargs[1], vargs[2]);
            else if(vargs[1])
                irc_send(irc, "%s %s %s :%s", cmd, target, vargs[0],
                    vargs[1]);
            else
                irc_send(irc, "%s %s %s", cmd, target, vargs[0]);
        }
    }
    g_strfreev(vargs);
    return 1;
}

int airc_usercmd_away(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    if(!strcasecmp(cmd, "back"))
        irc_send(irc, "AWAY");
    else{
        if(args && args[0] && strlen(args[0]))
            irc_send(irc, "AWAY :%s", args[0]);
        else
            irc_send(irc, "AWAY");
    }
    return 0;
}

int airc_usercmd_ctcp(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    char *ctcp, **msgargs;
    PurpleConnection *gc;
    
    gc = purple_account_get_connection(irc->account);
    if(!gc || !args || !args[0])
        return 0;
    msgargs = g_strsplit(args[0], " ", 3);
    if(!msgargs || !msgargs[0] || !msgargs[1])
        return 0;
    ctcp = g_ascii_strup(msgargs[1], -1);
    if(msgargs[2])
        irc_send(irc, "PRIVMSG %s :\001%s %s\001", msgargs[0], ctcp, msgargs[2]);
    else
        irc_send(irc, "PRIVMSG %s :\001%s\001", msgargs[0], ctcp);
    g_strfreev(msgargs);
    g_free(ctcp);
    return 0;
}

int airc_usercmd_invite(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    return 0;
}

int airc_usercmd_join(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    if(args[1])
        irc_send(irc, "JOIN %s %s", args[0], args[1]);
    else
        irc_send(irc, "JOIN %s", args[0]);
    return 0;
}

int airc_usercmd_kick(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    return airc_channel_cmd1(irc, "KICK", (char *)target, (char **)args);
}

int airc_usercmd_list(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    /*if(!args || !args[0])
        irc_send(irc, "LIST");
    else
        irc_send(irc, "LIST %s", args[0]);*/
    if(args && args[0])
        irc->listCmd = g_strdup_printf("LIST %s", args[0]);
    purple_roomlist_show_with_account(irc->account);
    return 0;
}

int airc_usercmd_me(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    char *action, *escaped, **msgar, **msgs, *msg;
    PurpleConnection *gc;
    PurpleConversation *convo;
    
    gc = purple_account_get_connection(irc->account);
    if(!gc || !args || !args[0])
        return 0;
    convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, target, irc->account);
    if(!convo)
        return 0;
    msgar = msgs = g_strsplit(args[0], "\n", -1);
    while((msg = *(msgs++))){
        irc_send(irc, "PRIVMSG %s :\001ACTION %s\001", target, msg);
        escaped = g_markup_escape_text(msg, -1);
        action = g_strdup_printf("/me %s", escaped);
        g_free(escaped);
        if(purple_conversation_get_type(convo) == PURPLE_CONV_TYPE_CHAT)
            serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)),
                purple_connection_get_display_name(gc),
                PURPLE_MESSAGE_SEND, action, time(NULL));
        else
            purple_conv_im_write(PURPLE_CONV_IM(convo), purple_connection_get_display_name(gc),
                action, PURPLE_MESSAGE_SEND, time(NULL));
        g_free(action);
    }
    g_strfreev(msgar);
    return 0;
}

int airc_usercmd_mode(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    PurpleConnection *gc;
    
    gc = purple_account_get_connection(irc->account);
    if(cmd && !strcasecmp(cmd, "UMODE")){
        irc_send(irc, "MODE %s :%s", purple_connection_get_display_name(gc),
            args[0]);
        return 0;
    }
    return airc_channel_cmd(irc, "MODE", (char *)target, (char **)args);
}

int airc_usercmd_notice(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    char *msg, **msgs, **msgar, **msgargs;
    
    msgargs = g_strsplit(args[0], " ", 2);
    msgar = msgs = g_strsplit(msgargs[1], "\n", -1);
    while((msg = *(msgs++))){
        irc_send(irc, "NOTICE %s :%s", msgargs[0], msg);
    }
    g_strfreev(msgargs);
    g_strfreev(msgar);
    return 0;
}

int airc_usercmd_part(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    char  **vargs;
    
    vargs = g_strsplit(args[0], " ", 2);
    if(airc_is_channel(irc, vargs[0])){
        if(vargs[1] && strlen(vargs[1]))
            irc_send(irc, "PART %s :%s", vargs[0], vargs[1]);
        else
            irc_send(irc, "PART %s", vargs[0]);
    }else{
        if(args[0] && strlen(args[0]))
            irc_send(irc, "PART %s :%s", target, args[0]);
        else
            irc_send(irc, "PART %s :%s", target,
                purple_account_get_string(irc->account, "partmessage", ""));
    }
    g_strfreev(vargs);
    return 0;
}

int airc_usercmd_ping(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    return 0;
}

int airc_usercmd_privmsg(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    char *msg, **msgs, **msgar, **msgargs;
    
    msgargs = g_strsplit(args[0], " ", 2);
    msgar = msgs = g_strsplit(msgargs[1], "\n", -1);
    while((msg = *(msgs++))){
        irc_send(irc, "PRIVMSG %s :%s", msgargs[0], msg);
    }
    g_strfreev(msgargs);
    g_strfreev(msgar);
    return 0;
}

int airc_usercmd_query(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    PurpleConversation *convo;
    PurpleConnection *gc;
    char **msgargs, *msgs[2] = {NULL, NULL};

    if(!args || !args[0])
        return 0;
    msgargs = g_strsplit(args[0], " ", 2);
    if(!msgargs || !msgargs[0])
        return 0;
    convo = purple_conversation_new(PURPLE_CONV_TYPE_IM, irc->account,
        msgargs[0]);
    purple_conversation_present(convo);
    if(msgargs[1]){
        gc = purple_account_get_connection(irc->account);
        msgs[0] = g_strjoinv(" ", msgargs);
        airc_usercmd_privmsg(irc, cmd, target, (const char**)msgs);
        purple_conv_im_write(PURPLE_CONV_IM(convo),
            purple_connection_get_display_name(gc), msgargs[1],
            PURPLE_MESSAGE_SEND, time(NULL));
        g_free(msgs[0]);
    }

    return 0;
}

int airc_usercmd_quit(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    if(!args || !args[0]){
        irc_send(irc, "QUIT :%s", purple_account_get_string(irc->account,
            "quitmessage", IRC_DEFAULT_QUIT));
    }else{
        irc_send(irc, "QUIT :%s", args[0]);
    }
    return 0;
}

int airc_usercmd_quote(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    irc_send(irc, "%s", args[0]);
    return 0;
}

int airc_usercmd_topic(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    return airc_channel_cmd(irc, "TOPIC", (char *)target, (char **)args);
    /*char **vargs;
    
    if(!args)
        return 0;
    vargs = g_strsplit(args[0], " ", 2);
    if(airc_is_channel(irc, vargs[0])){
        if(vargs[1])
            irc_send(irc, "TOPIC %s :%s", vargs[0], (vargs[1][0] == ':') ?
                vargs[1]+1 : vargs[1]);
        else
            irc_send(irc, "TOPIC %s", vargs[0]);
    }else{
        if(airc_is_channel(irc, (char *)target)){
            if(vargs[0])
                irc_send(irc, "TOPIC %s :%s", target, (vargs[0][0] == ':') ?
                    vargs[0]+1 : vargs[0]);
            else
                irc_send(irc, "TOPIC %s", target);
        }
    }
    return 0;*/
}

int airc_usercmd_whois(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    if(!args)
        return 0;
    if(args[1])
        irc_send(irc, "WHOIS %s %s", args[0], args[1]);
    else
        irc_send(irc, "WHOIS %s", args[0]);
    return 0;
}

int airc_usercmd_whowas(IRC_conn *irc, const char *cmd, const char *target, const char **args){
    if(!args)
        return 0;
    irc_send(irc, "WHOWAS %s", args[0]);
    return 0;
}

